﻿using System;
using System.Collections.Generic;
using System.IO;
using GameFramework.configs;
using GameFramework.net.events;
using UnityEngine;

namespace GameFramework.net
{
    public class LengthFieldBasedFrameDecoder
    {
        private int maxCacheSize = 1024 * 24 *2;//8M
        //中间变量来处理半包/粘包问题
        private MemoryStream _writer ;
        private  int maxFrameLength;//帧的最大长度
        private  int lengthFieldOffset;
        private  int lengthFieldLength;
        private  int lengthFieldEndOffset;
        private  int lengthAdjustment;
        private  int initialBytesToStrip;
        private long tooLongFrameLength;
        private long bytesToDiscard;
        private int frameLengthInt = -1;
        public bool socketDataIsBig = true;//网络字节序时大端还是小端，默认大端(服务端netty默认是大端的)
        public LengthFieldBasedFrameDecoder()
        {
            _writer = new MemoryStream();
            maxFrameLength = maxCacheSize / 2;
        }

        public List<MsgWrapper> addBytes(byte[] newBytes,int offset,int count)
        {
            List<MsgWrapper> result = new List<MsgWrapper>();
            //tou(数据长度4字节)+数据内容
            // int socketDataLen = newBytes.Length;
            // if (socketDataLen > maxFrameLength)
            // {
            //     Debug.LogError("收到数据长度大于帧最大值："+maxFrameLength+"  数据丢弃");
            //     return result;
            // }

            _writer.Seek(_writer.Length, SeekOrigin.Begin);
            //写
            _writer.Write(newBytes,offset,count);

            //读 网络字节序默认大端(netty中默认字节序是大端字节序，即字节高位在前，低位在后，符合人类的书写习惯，需要需要自定义，需要额外代码)
            _writer.Seek(0, SeekOrigin.Begin);
            if (_writer.Length < MsgWrapper.MsgHeadLenth)//不够消息头长度
            {
                return result;
            }
            
            int readIndex = 0;
            //TODO 对数据进行反序列化或交给下一个pipline处理
            while (_writer.Length - _writer.Position >= MsgWrapper.MsgHeadLenth)//可以一直获取数据
            {
                int moshu = MemoryStreamHelper.readShort(_writer) & 0xff;
                //todo 与配置的魔术进行比较
                if (moshu != LocalConfig.Instance.msgConfig.moshu)
                {
                    MoshuNotMatchEvent e = new MoshuNotMatchEvent();
                    e.msgMoshu = moshu;
                    EventManager.Instance.dispatch(e);
                    //魔术号不对
                    break;
                }

                int dataLen = MemoryStreamHelper.readInt(_writer);
                Debug.Log("数据长度："+dataLen+" 数据读索引："+_writer.Position+" 数据缓存长度："+_writer.Length);
                if ((_writer.Length -_writer.Position <dataLen) && readIndex>0)//消息体长度不够，且不是第一个消息
                {
                    _writer.Seek(readIndex, SeekOrigin.Begin);
                    //TODO 将剩余的数据拷贝到流的开始位置，好继续接收下一个网络数据帧
                    long remainLen = _writer.Length-readIndex;
                    byte[] remainBytes = new byte[remainLen];
                    _writer.Read(remainBytes);
                    _writer.Seek(0, SeekOrigin.Begin);
                    _writer.SetLength(0);
                    _writer.Write(remainBytes);
                    break;
                }
                
                readIndex += 4 + dataLen;
                byte[] data = new byte[dataLen];
                _writer.Read(data);
                // result.Add(data);
            }

            return result;
        }
    } 
}